package test;

import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.core.AID;
import jade.core.ServiceException;
import jade.core.messaging.TopicManagementHelper;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.util.Logger;

import java.util.logging.Level;

import test.common.TesterAgent;
import de.fhin.mas.MASEvents;
import de.fhin.mas.MASServices;
import de.fhin.mas.ontology.MASOntology;

/**
 * Abstrakte Basisklasse fuer Test-Agenten. Stellt u.a. Logging-Funktionalitaet
 * zur Verfuegung.
 * 
 * @author Alexander Weickmann
 */
public abstract class BaseTestAgent extends TesterAgent {

	// ************************************************************
	// *** ontologierelevantes Zeug hier drin: ***
	private final Codec codec = new SLCodec();

	private final Ontology ontology = MASOntology.getInstance();
	// ************************************************************

	/** Die eindeutige ID zur Serialisierung ueber das Netzwerk. */
	private static final long serialVersionUID = 519789641981499518L;

	/** Logger zum Loggen von Fehlern. */
	private final Logger logger;

	/** Eine Referenz auf den zu testenden Agenten. */
	private AID agentToTest;

	/** Der Service der getestet werden soll. */
	private final MASServices serviceToTest;

	/** Helper zum Handling der Topics. */
	private TopicManagementHelper topicHelper;

	/** Erzeugt den <tt>BaseTestAgent</tt>. */
	public BaseTestAgent(MASServices serviceToTest) {
		this.logger = Logger.getMyLogger(this.getClass().getName());
		this.serviceToTest = serviceToTest;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void setup() {
		super.setup();

		// ************************************************************
		// *** ontologierelevantes Zeug hier drin: ***
		getContentManager().registerLanguage(codec);
		getContentManager().registerOntology(ontology);
		// ************************************************************

		registerWithPlatform();
		initTopicHelper();
		searchAgentToBeTested();
	}

	/**
	 * Registriert den Tester-Agent bei der Agentenplattform. Der Tester-Agent
	 * bietet alle Services an.
	 */
	private void registerWithPlatform() {
		DFAgentDescription dfd = new DFAgentDescription();
		for (MASServices currentService : MASServices.values()) {
			dfd.addServices(currentService.getServiceDescription());
		}
		ServiceDescription testerDescription = new ServiceDescription();
		testerDescription.setType("Tester");
		testerDescription.setName(getName());
		dfd.addServices(testerDescription);
		dfd.setName(getAID());

		try {
			DFService.register(this, dfd);
		} catch (FIPAException e) {
			log(Level.SEVERE, getName() + ": registration with agent platform failed.", e);
			doDelete();
		}
		log(Level.INFO, getName() + ": succeeded in registration with agent platform.");
	}

	/** Bei der Plattform nach einem zu testenden, registrierten Agenten fragen. */
	private void searchAgentToBeTested() {
		try {
			agentToTest = MASServices.findService(this, serviceToTest);
			if (agentToTest == null) {
				log(Logger.INFO, getName() + ": could not find the agent to test within the agent platform, shutting down agent");
				doDelete();
			}
		} catch (FIPAException e) {
			log(Logger.SEVERE, getName()
					+ ": an error occured while searching the agent platform for the agent to test, shutting down agent", e);
			doDelete();
		}
	}

	/**
	 * Registriere den Agenten für ein bestimmtes Topic bei der Plattform.
	 * 
	 * @param topic
	 *            Das Topic für welches der Agent registriert werden soll.
	 * @return Objekt, das in Message-Templates zum Filtern auf Topic verwendet
	 *         werden kann.
	 */
	public AID subscribeToTopic(MASEvents topic) {
		return topicHelper.createTopic(topic.getName());
	}

	/**
	 * ACHTUNG: Zusätzlicher Start-Parameter
	 * "-services jade.core.messaging.TopicManagementService" notwendig, damit
	 * Initialisierung klappt!
	 * 
	 */
	private void initTopicHelper() {
		try {
			topicHelper = (TopicManagementHelper) getHelper(TopicManagementHelper.SERVICE_NAME);
		} catch (ServiceException e) {
			logger.log(Logger.WARNING, "Initializing the TopicManagementHelper failed!", e);
			logger.log(Logger.WARNING,
					"Please add start argument ''-services jade.core.messaging.TopicManagementService''!");
			doDelete();
		}
	}

	/**
	 * Loggt einen Fehler.
	 * 
	 * @param level
	 *            Der Schweregrad des Fehlers.
	 * @param msg
	 *            Eine Kurzbeschreibung des Fehlers.
	 * @param e
	 *            Die aufgetretene Exception.
	 */
	public void log(Level level, String msg, Throwable e) {
		logger.log(level, msg, e);
	}

	/**
	 * Loggt einen Fehler.
	 * 
	 * @param level
	 *            Der Schweregrad des Fehlers.
	 * @param msg
	 *            Eine Kurzbeschreibung des Fehlers.
	 */
	public void log(Level level, String msg) {
		logger.log(level, msg);
	}

	/** Gibt die <tt>AID</tt> des zu testenden Agenten zurueck. */
	public AID getAgentToTest() {
		return agentToTest;
	}

	/**
	 * Gibt den verwendeten Content Language Codec zurück
	 * 
	 * @return Codec
	 */
	public Codec getCodec() {
		return codec;
	}

	/**
	 * Gibt die verwendete Ontologie zurück
	 * 
	 * @return Ontologie
	 */
	public Ontology getOntology() {
		return ontology;
	}

}
